#include "unit.h"
#include<stdlib.h>
#include<stdarg.h>
Unit* newunit(unsigned int nin,unsigned int nout,void(*action)(Unit*),
void(*update)(Unit*)){
	Unit* v=(Unit*)malloc(sizeof(Unit));
	v->nin=nin,v->nout=nout;
	v->action=action,v->update=update;
	v->in=(InPack*)calloc(nin,sizeof(InPack));
	v->out=(OutPack*)calloc(nout,sizeof(OutPack));
	v->ismodule=0;
	return v;
}
static void moduleaction(Unit* v){
	unsigned int m=v->nin;
	InPack* p=v->in;
	for(unsigned int i=0;i<m;i++){
		v=p[i].in;
		v->action(v);
	}
}
static void moduleupdate(Unit* v){
	unsigned int m=v->nin,n=v->nout;
	InPack* p=v->in;
	OutPack* op=v->out,*vp;
	for(unsigned int i=0;i<m;i++){
		v=p[i].in;
		v->update(v);
	}
	for(unsigned int i=0;i<n;i++){
		v=p[i].in;
		vp=&op[i];
		vp->value=v->out[vp->cache].value;
	}
}
Unit* newmodule(unsigned int nin,unsigned int nout,...){
	Unit* v=newunit(nin,nout,moduleaction,moduleupdate);
	v->ismodule=1;
	va_list ap;
	unsigned int i=0;
	va_start(ap,nout);
	while(i<nout){
		InPack* p=&v->in[i];
		p->in=va_arg(ap,Unit*);
		p->outport=va_arg(ap,unsigned int);
		v->out[i++].cache=va_arg(ap,unsigned int);
	}
	while(i<nin){
		InPack* p=&v->in[i++];
		p->in=va_arg(ap,Unit*);
		p->outport=va_arg(ap,unsigned int);
	}
	va_end(ap);
	return v;
}
void freeunit(Unit* v){
	if(v->ismodule){
		unsigned int n=v->nin;
		InPack* p=v->in;
		while(n--)freeunit(p[n].in);
	}
	free(v->in);
	free(v->out);
	free(v);
}
void rununits(Unit** units,size_t nunit){
	for(size_t i=0;i<nunit;i++){
		Unit* cur=units[i];
		cur->action(cur);
	}
	for(size_t i=0;i<nunit;i++){
		Unit* cur=units[i];
		cur->update(cur);
	}
}
void connectunit(Unit* from,unsigned int outport,Unit* to,unsigned int inport){
	InPack* p=&to->in[inport];
	if(to->ismodule)p=&p->in->in[p->outport];
	p->in=from;
	p->outport=outport;
}